import {deepCopy, generateUID,formatLinearColor} from "@/utils";
import {WidgetFactory} from "../../widgetFactory";
const objectHash = require('object-hash');

export class WidgetClass {
  constructor(options = {}) {
    const {
      _id, roomId, componentId, subPageId, relateSubPage, relateSubPageId,
      parentId = '', id = '', editId = '', sourceId,
      hash = '', visible = true, display = true, isRoot = false,
      droppable = false, draggable = true, resizable = true, selectable = true,
      isLocked = false, isFreeze = false, isChildrenFreeze = false, isEditing = false,
      type = '', category = '', isAppendage = false,appendageId='',appendDialogId='', name = '', rect = {}, sortNo = 1, isDeleted = false,
      UI = {state: null, states: [], data: null}, ports,
      syncToFactory = true, editableByControl = false
    } = options;

    this.hash = hash; // 用于判断 widget 是否发生更改
    this.curHash = hash; // 用于记录 widget 当前的 hash 值，用于与原始 hash 做对比
    this._id = _id;
    this.id = id || generateUID();
    this.editId = editId || this.id;
    this.parentId = parentId;
    this.sourceId = sourceId; // 拷贝组件时缓存被拷贝原组件的 id
    this.roomId = roomId; // 用于房间编辑时 widget 关联房间
    this.componentId = componentId; // 用于组件制作中 widget 关联所属的组件 id
    this.subPageId = subPageId; // 用于组件制作中 widget 关联所属的子页面 id，用于 WidgetPicker 的组件选则
    this.relateSubPage = relateSubPage; // 标志主页关联至子页面
    this.relateSubPageId = relateSubPageId; // 主页关联至子页面的 id
    this.editableByControl = editableByControl; // 组件变量是否能被分控更改
    this.type = type; // page/subPage/component
    this.category = category;
    this.isAppendage = isAppendage; // 标志是否为附属内容，比如详情页
    this.appendageId=appendageId; // 附属详情页组件的id
    this.appendDialogId=appendDialogId; // 附属全局弹框组件的id
    this.name = name || category;
    const {width = 0, height = 0, top = 0, left = 0} = rect;
    this.rect = {width, height, top, left};
    this.tempRect = {width, height, top, left}; // rect 过程变量，用于实时计算，比如辅助对齐线、RectControl 组件的显示
    this.UI = UI;
    this.ports = ports || this.assembleDefaultPorts();
    this.isRoot = isRoot;
    this.display = display; // 用于编辑过程中的调试
    this.displayForPicker = display; // 组件选择器的组件显示状态需要做字段区分
    this.visible = visible; // 组件的默认显示状态
    this.active = false;
    this.activeForPicker = false; // 组件选择器的组件激活状态需要做字段区分
    this.draggable = draggable;
    this.isDragging = false;
    this.droppable = droppable;
    this.resizable = resizable;
    this.isResizing = false;
    this.selectable = selectable;
    this.isLocked = isLocked;
    this.isFreeze = isFreeze; // 冻结组件，用于方便选中父组件进行移动位置
    this.isChildrenFreeze = isChildrenFreeze; // 标志子组件是否冻结
    this.isEditing = isEditing; // 标识自定义组件是否处于编辑状态
    this.isDeleted = isDeleted;
    this.sortNo = sortNo;
    this.children = [];
    this.expandedEvent = []; // 记录组件当前展开的事件列表展开状态
    this.isHover = false; // 标志正在对组件拖拽创建子组件
    this.hideStick = false; // 标志是否不显示 sticks
    // rect 对齐辅助线
    this.snapLine = [];
    this.gaps = [];
    // rect 与父组件的垂直、水平间距
    this.topLine = [];
    this.leftLine = [];
    this.bottomLine = [];
    this.rightLine = [];
    // UI states 初始化处理
    if (UI.states && UI.states.length > 0) {
      this.UI.states = UI.states;
      this.UI.state = UI.state;
    } else {
      const defaultState = this.assembleDefaultState(options);
      this.UI.states = [defaultState];
      this.UI.state = defaultState.id;

      // 按钮增加默认+激活状态
      if (this.category === 'iconButton') {
        this.addIconButtonState();
      } else if (this.category === 'iconTextButton') {
        this.addIconButtonTextState();
      }
    }
    // 对于新创建的 widget，初始化时创建原始 hash
    !this.hash && (this.curHash = generateWidgetHash(this));
    // 组件创建时，同步至工厂 production
    syncToFactory && WidgetFactory.syncToFactory(this);
  }

  addIconButtonState() {
    let lastState = deepCopy(this.UI.states[this.UI.states.length - 1]);
    lastState.backStyle.backgroundColor = "brand-color";
    lastState.iconStyle.color = "text-color-anti";
    const stateId = this.UI.states.length.toString();
    this.UI.states.push({
      ...lastState,
      id: stateId,
      stateName: `激活状态`,
    });
  }
  addIconButtonTextState() {
    let lastState = deepCopy(this.UI.states[this.UI.states.length - 1]);
    lastState.backStyle.backgroundColor="brand-color"
    lastState.iconStyle.color="text-color-anti"
    lastState.textStyle.color="text-color-anti"
    const stateId = this.UI.states.length.toString();
    this.UI.states.push({
      ...lastState,
      id: stateId,
      stateName: `激活状态`,
    });
  }

  assembleDefaultPorts() {
    return {
      values: [
        {
          name: "显隐",
          key: "visible",
          type: "bool",
          value: true,
        },
        {
          name: "状态",
          key: "state",
          type: "int",
          value: 0,
        },
      ],
      events: [
        {
          name: "抬起事件",
          key: `onTap-${this.id}`,
          eventType: "onTap",
          type: "event",
          action: [],
        },
        {
          name: "按下事件",
          key: `tapDown-${this.id}`,
          type: "event",
          eventType: "tapDown",
          action: [],
        },
        {
          name: "长按事件",
          key: `longPress-${this.id}`,
          eventType: "longPress",
          type: "event",
          value: {
            time: 1 //长按触发时间(秒)
          },
          action: [],
        },
        {
          name: "初始化事件",
          key: `init-${this.id}`,
          type: "event",
          eventType: "init",
          action: [],
        },
      ],
    };
  }

  assembleDefaultState(options) {
    const {backStyle, textStyle, iconStyle,values} = options;
    return {
      id: '0',
      backStyle: initStyle(backStyle),
      textStyle: textStyle,
      iconStyle: iconStyle,
      values: values,
      stateName: "默认状态",
    };
  }

  addState() {
    const lastState = deepCopy(this.UI.states[this.UI.states.length - 1]);
    const stateId = this.UI.states.length.toString();
    this.UI.states.push({
      ...lastState,
      id: stateId,
      stateName: `state-${this.UI.states.length}`,
    });
    this.UI.state = stateId;
  }

  removeState(id = "") {
    const idx = this.UI.states.findIndex(state => state.id === id);
    if (!!~idx) {
      if (this.UI.states[idx].id === this.UI.state) {
        this.UI.state = this.UI.states[idx - 1].id;
      }
      this.UI.states.splice(idx, 1);
    }
  }

  getCurrentState() {
    let curState = this.UI.states.find((state) => state.id === this.UI.state);
    if (!curState) {
      curState = this.UI.states[this.UI.states.length - 1];
    }
    this.UI.state = curState.id;
    return curState;
  }

  // 计算子组件与父组件之间的水平、垂直间距
  calcSpaceLine() {
    const parent = WidgetFactory.getWidgetById(this.parentId);
    if (!parent) return;
    const topLine = [], rightLine = [], bottomLine = [], leftLine = [];
    const {width: pWidth = 0, height: pHeight = 0} = parent.tempRect;
    const {top = 0, left = 0, width = 0, height = 0} = this.tempRect;

    // 与父组件的间距
    topLine.push({top: -top, left: Math.floor(width / 2), height: top});
    rightLine.push({top: Math.floor(height / 2), left: width, width: pWidth - left - width});
    bottomLine.push({top: height, left: Math.floor(width / 2), height: pHeight - top - height});
    leftLine.push({top: Math.floor(height / 2), left: -left, width: left});

    this.topLine = topLine;
    this.rightLine = rightLine;
    this.bottomLine = bottomLine;
    this.leftLine = leftLine;
  }

  hideSpaceLine() {
    this.topLine = [];
    this.rightLine = [];
    this.bottomLine = [];
    this.leftLine = [];
  }

  // 计算是否显示 widget 对齐基准线
  calcSnapLine() {
    const parent = WidgetFactory.getWidgetById(this.parentId);
    if (!parent) return;
    const snapLine = [];

    function judgeEqual(a, b) {
      return Math.floor(a) === Math.floor(b);
    }

    const {tempRect: pRect = {}, children = []} = parent;
    const {width: pWidth = 0, height: pHeight = 0} = pRect;
    const {top = 0, left = 0, width = 0, height = 0} = this.tempRect;
    // 与父组件垂直居中
    if (judgeEqual(top + height / 2, pHeight / 2)) {
      snapLine.push({type: "h", top: top + height / 2});
    }
    // 与父组件水平居中
    if (judgeEqual(left + width / 2, pWidth / 2)) {
      snapLine.push({type: "v", left: left + width / 2});
    }
    // 当前组件上与父组件垂直中点对齐
    if (judgeEqual(top, pHeight / 2)) {
      snapLine.push({type: "h", top: top});
    }
    // 当前组件下与父组件垂直中点对齐
    if (judgeEqual(top + height, pHeight / 2)) {
      snapLine.push({type: "h", top: top + height});
    }
    // 当前组件左与父组件水平中点对齐
    if (judgeEqual(left, pWidth / 2)) {
      snapLine.push({type: "v", left: left});
    }
    // 当前组件右与父组件水平中点对齐
    if (judgeEqual(left + width, pWidth / 2)) {
      snapLine.push({type: "v", left: left + width});
    }
    children.forEach((child) => {
      if (child.isDeleted || !child.display) return;
      if (child.id === this.id) return;
      const {width: cWidth = 0, height: cHeight = 0, top: cTop = 0, left: cLeft = 0,} = child.tempRect;
      // 与兄弟组件水平居中对齐
      if (judgeEqual(top + height / 2, cTop + cHeight / 2)) {
        snapLine.push({type: "h", top: top + height / 2});
      }
      // 与兄弟组件垂直居中对齐
      if (judgeEqual(left + width / 2, cLeft + cWidth / 2)) {
        snapLine.push({type: "v", left: left + width / 2});
      }
      // 与兄弟组件上对齐
      if (judgeEqual(top, cTop)) {
        snapLine.push({type: "h", top: top});
      }
      // 与兄弟组件左对齐
      if (judgeEqual(left, cLeft)) {
        snapLine.push({type: "v", left: left});
      }
      // 与兄弟组件下对齐
      if (judgeEqual(top + height, cTop + cHeight)) {
        snapLine.push({type: "h", top: top + height});
      }
      // 与兄弟组件右对齐
      if (judgeEqual(left + width, cLeft + cWidth)) {
        snapLine.push({type: "v", left: left + width});
      }
      // 当前组件上与兄弟组件下对齐
      if (judgeEqual(top, cTop + cHeight)) {
        snapLine.push({type: "h", top: top});
      }
      // 当前组件下与兄弟组件上对齐
      if (judgeEqual(top + height, cTop)) {
        snapLine.push({type: "h", top: top + height});
      }
      // 当前组件上与兄弟组件水平中点对齐
      if (judgeEqual(top, cTop + cHeight / 2)) {
        snapLine.push({type: "h", top: top});
      }
      // 当前组件下与兄弟组件水平中点对齐
      if (judgeEqual(top + height, cTop + cHeight / 2)) {
        snapLine.push({type: "h", top: top + height});
      }
      // 当前组件左与兄弟组件右对齐
      if (judgeEqual(left, cLeft + cWidth)) {
        snapLine.push({type: "v", left: left});
      }
      // 当前组件右与兄弟组件左对齐
      if (judgeEqual(left + width, cLeft)) {
        snapLine.push({type: "v", left: left + width});
      }
      // 当前组件左与兄弟组件垂直中点对齐
      if (judgeEqual(left, cLeft + cWidth / 2)) {
        snapLine.push({type: "v", left: left});
      }
      // 当前组件右与兄弟组件垂直中点对齐
      if (judgeEqual(left + width, cLeft + cWidth / 2)) {
        snapLine.push({type: "v", left: left + width});
      }
    });
    parent.snapLine = snapLine;
  }

  hideSnapLine() {
    const parent = WidgetFactory.getWidgetById(this.parentId);
    if (!parent) return;
    parent.snapLine = [];
  }

  // 计算所有子组件之间的水平、垂直间距
  calcChildrenGap(type = "") {
    const gaps = [];
    for (let i = 0; i < this.children.length; i++) {
      const child = this.children[i];
      const nextChild = this.children[i + 1];
      if (child && nextChild) {
        switch (type) {
          case "horizontal":
            gaps.push(nextChild.rect.left - child.rect.left - child.rect.width);
            break;
          case "vertical":
            gaps.push(nextChild.rect.top - child.rect.top - child.rect.height);
            break;
          default:
            break;
        }
      }
    }
    return gaps;
  }
}

export function generateWidgetHash(widget = {}) {
  const destWidget = {};
  widgetHashKeys.forEach(key => destWidget[key] = widget[key]);
  return objectHash(destWidget, {
    respectFunctionProperties: false,
    respectType: false
  });
}

// 与 hash 计算相关的属性 key
export const widgetHashKeys = [
  'id', 'editId', 'parentId', 'name', 'rect', 'UI', 'ports',
  'display', 'visible', 'draggable', 'droppable', 'resizable',
  'selectable', 'isLocked', 'isFreeze', 'isChildrenFreeze',
  'isEditing', 'editableByControl', 'isDeleted', 'sortNo'
];
export function getDefaultStyle() {
  return {
    backgroundColor: "#FFFFFF",
    backgroundImage: "",
    border: {
      width: 0,
      color: "",
      top: {width: 0, color: ""},
      left: {width: 0, color: ""},
      bottom: {width: 0, color: ""},
      right: {width: 0, color: ""},
    },
    borderRadius: {
      width: 0,
      topLeft: 0,
      topRight: 0,
      bottomLeft: 0,
      bottomRight: 0,
    },
    shadow: {
      xOffset: 0,
      yOffset: 0,
      blur: 0,
      spread: 0,
      color: "",
      type: "",
    },
    linearGradient:{
      direction:'right',
      colors:[]
    }
  };
}

export function initStyle(style = {}) {
  // 将传入的初始样式和默认样式合并
  function combineStyle(object = {}, srcObj = {}) {
    const dest = {};
    Object.keys(object).forEach((key) => {
      const value = object[key];
      if (_.isObject(value)) {
        dest[key] = combineStyle(value, srcObj[key]);
      } else {
        dest[key] = srcObj[key] || value;
      }
    });
    return dest;
  }

  const defaultStyle = getDefaultStyle();
  const destStyle = combineStyle(defaultStyle, style);
  // 同步边框和圆角的全局和局部设置值
  const {border = {}, borderRadius = {}} = destStyle;
  const {width: bWidth = 0, color: bColor = "#FFFFFF"} = border;
  const {width: brWidth = 0} = borderRadius;
  if (bWidth) {
    border.top.width = bWidth;
    border.left.width = bWidth;
    border.bottom.width = bWidth;
    border.right.width = bWidth;
  }
  if (bColor) {
    border.top.color = bColor;
    border.left.color = bColor;
    border.bottom.color = bColor;
    border.right.color = bColor;
  }
  if (brWidth) {
    borderRadius.topLeft = brWidth;
    borderRadius.topRight = brWidth;
    borderRadius.bottomLeft = brWidth;
    borderRadius.bottomRight = brWidth;
  }
  return destStyle;
}

export function getBasicStyles(style = {}) {
  const styles = {};
  // 边框
  const {backStyle = {}} = style;
  const {border = {}, borderRadius = {}, shadow = {},linearGradient={}} = backStyle;
  const {
    width: bWidth = 0,
    color: bColor = "",
    top: bTop = {},
    left: bLeft = {},
    bottom: bBottom = {},
    right: bRight = {},
  } = border;
  const {width: btWidth = 0, color: btColor = ""} = bTop;
  const {width: blWidth = 0, color: blColor = ""} = bLeft;
  const {width: bbWidth = 0, color: bbColor = ""} = bBottom;
  const {width: brWidth = 0, color: brColor = ""} = bRight;
  bWidth && bColor && (styles.border = `${bWidth}px ${bColor} solid`);
  btWidth && btColor && (styles.borderTop = `${btWidth}px ${btColor} solid`);
  blWidth && blColor && (styles.borderLeft = `${blWidth}px ${blColor} solid`);
  bbWidth && bbColor && (styles.borderBottom = `${bbWidth}px ${bbColor} solid`);
  brWidth && brColor && (styles.borderRight = `${brWidth}px ${brColor} solid`);
  // 圆角
  const {
    width: brgWidth = 0,
    topLeft = 0,
    topRight = 0,
    bottomLeft = 0,
    bottomRight = 0,
  } = borderRadius;
  if (brgWidth) {
    borderRadius.topLeft = brgWidth;
    borderRadius.topRight = brgWidth;
    borderRadius.bottomLeft = brgWidth;
    borderRadius.bottomRight = brgWidth;
  }
  topLeft && (styles.borderTopLeftRadius = `${topLeft}px`);
  topRight && (styles.borderTopRightRadius = `${topRight}px`);
  bottomLeft && (styles.borderBottomLeftRadius = `${bottomLeft}px`);
  bottomRight && (styles.borderBottomRightRadius = `${bottomRight}px`);

  // 阴影
  const {
    xOffset = 0,
    yOffset = 0,
    blur = 0,
    spread = 0,
    color = "",
    type = "",
  } = shadow;
  color &&
  (styles.boxShadow = `${xOffset}px ${yOffset}px ${blur}px ${spread}px ${color} ${type}`);
  //渐变色
  const { direction='right', colors=[]}=linearGradient
  if(colors.length){
    styles.background =  `linear-gradient(${formatLinearColor(direction)}, ${colors.join(',')})`
  }
  return styles;
}
